package service

import (
	"context"
	"fmt"
	"go.uber.org/atomic"
	"golang.org/x/exp/rand"
	"syntax/webook/internal/repository"
	"syntax/webook/internal/service/sms"
)

var (
	ErrCodeSendTooMany        = repository.ErrCodeSendTooMany
	ErrCodeVerifyTooManyTimes = repository.ErrCodeVerifyTooManyTimes
)

type CodeService interface {
	Send(ctx context.Context,
		// 区别业务场景
		biz string, phone string) error
	Verify(ctx context.Context, biz string,
		phone string, inputCode string) (bool, error)
}

type codeService struct {
	repo   repository.CodeRepository
	smsSvc sms.Service
	//tplId string
}

// const codeTplId = "1877556"
var codeTplId atomic.String = atomic.String{}

func NewCodeService(repo repository.CodeRepository, smsSvc sms.Service) CodeService {
	codeTplId.Store("1877556")
	//viper.OnConfigChange(func(in fsnotify.Event) {
	//	codeTplId.Store(viper.GetString("code.tpl.id"))
	//})
	return &codeService{
		repo:   repo,
		smsSvc: smsSvc,
	}
}

// Send发送验证码  需要什么参数
func (svc *codeService) Send(ctx context.Context,
	// 区别使用业务
	biz string,
	phone string) error {
	//code := "12345"
	//setToRedis(code, time.Second*300)

	// 3个步骤， 生成一个验证码， /***/ set ->redis  发送出去
	code := svc.generateCode()
	// 塞入 redis
	err := svc.repo.Store(ctx, biz, phone, code)
	if err != nil {
		// 有问题
		return err
	}
	// 这前面成功了

	// 发送出去

	err = svc.smsSvc.Send(ctx, codeTplId.Load(), []string{code}, phone)
	if err != nil {
		err = fmt.Errorf("发送短信出现异常 %w", err)
	}

	//if errs != nil {
	// 这里如何处理？
	// 这意味着redis有验证码，但是没有发送成功，用户收不到
	// 能不能删掉这个验证码?
	// 这个 errs 可能是超时的 errs, 你到不知道发出去了没
	// 重试？
	// 要重试的话 传初始化的时候， 给一个自己就会重试的 smsSVC
	//}
	return err

}

func (svc *codeService) Verify(ctx context.Context,
	biz string,
	phone string,
	inputCode string) (bool, error) {
	// phone_code:$biz:153xxxxxx
	// code:$biz:153xxxxxx
	// $biz:code:152xxxxxx
	// user:login:153xxxxx
	return svc.repo.Verify(ctx, biz, phone, inputCode)

}

func (svc *codeService) generateCode() string {
	// 六位数： nums 在 0 到 99999 之间  包含 0 - 99999
	nums := rand.Intn(1000000)
	// 不够六位的，加上前导0
	//
	return fmt.Sprintf("%6d", nums)
}

//func (svc *CodeService) VerifyV1(ctx context.Context,
//	biz string, phone string,
//	inputCode string) error {
//
//}
